package com.baijiayun.liveuibase.base;

import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.UiThread;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

import com.baijiayun.liveuibase.utils.ShadowUtil;
import com.baijiayun.liveuibase.utils.ToastUtil;

import io.reactivex.disposables.CompositeDisposable;

/**
 * Created by Shubo on 2018/9/7.
 */
public abstract class BaseWindow implements IWindow, LifecycleObserver {
    protected View view;
    private boolean controllable = true;
    private boolean needShowShadow = false;
    protected ShadowUtil boundView;
    private int z = 0;
    protected GestureDetector gestureDetector;
    private OnSingleTapListener onSingleTapListener;
    private OnDoubleTapListener onDoubleTapListener;
    protected OnWindowRepositionListener onWindowRepositionListener;
    protected boolean allowTouch;
    protected Context context;
    private Lifecycle lifecycle;
    protected QueryPlus $;
    protected RouterListener routerListener;
    private boolean isDestroy = false;
    protected CompositeDisposable compositeDisposable = new CompositeDisposable();


    @UiThread
    public BaseWindow(Context context) {
        this.context = context;
        if (context instanceof RouterListener) {
            this.routerListener = (RouterListener) context;
        } else {
            throw new RuntimeException("context not extend RouterListener");
        }
        this.lifecycle = routerListener.getLifecycle();
        allowTouch = routerListener.getLiveRoom() != null && routerListener.getLiveRoom().isTeacherOrAssistant();
        lifecycle.addObserver(this);
        doOnCreateView(context);
        view = onCreateView(context);
        $ = QueryPlus.with(view);
        if (needShowShadow) {
            boundView = ShadowUtil.setViewBoundShadow(view);
        }
        view.setOnTouchListener(new WindowOnTouchListener());
        gestureDetector = new GestureDetector(view.getContext(), new WindowGestureDetector());
    }

    /**
     * 在onCreateView之前调用
     * @param context
     */
    protected void doOnCreateView(Context context) {

    }

    protected abstract View onCreateView(Context context);

    protected void showToastMessage(String msg) {
        if (view != null && view.getContext() != null) {
            new ToastUtil(view.getContext()).setText(msg).create().show();
        }
    }

    @Override
    public View getView() {
        return view;
    }

    @Override
    public int getOrderInLayer() {
        ViewGroup viewGroup = getParentViewGroup();
        if (viewGroup == null) {
            return z;
        }
        return z == 0 ? viewGroup.indexOfChild(view) : z;
    }

    /**
     * 最大化窗口
     */
    @Override
    public void maximize() {
        ViewGroup.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        view.setLayoutParams(layoutParams);
    }

    /**
     * 当前用户是否有操作权限
     *
     * @return 控制权限
     */
    @Override
    public boolean controllable() {
        return controllable;
    }


    private ValueAnimator animatorX;
    private int lastLeft, lastTop;

    private void animateMoveTo(int x, int y) {
        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();
        if (animatorX != null && animatorX.isRunning()) {
            // 兼容信令发送特别频繁的情况
            layoutParams.leftMargin = lastLeft;
            layoutParams.topMargin = lastTop;
            animatorX.cancel();
            if (view != null) {
                view.requestLayout();
            }
        }
        lastLeft = x;
        lastTop = y;
        int originY = layoutParams.topMargin;
        int offsetY = y - originY;
        animatorX = ValueAnimator.ofInt(layoutParams.leftMargin, x);
        animatorX.addUpdateListener(animation -> {
            layoutParams.leftMargin = (int) animation.getAnimatedValue();
            layoutParams.topMargin = (int) (originY + animation.getAnimatedFraction() * offsetY);
            if (view != null) {
                view.requestLayout();
            } else {
                animation.cancel();
            }
        });
        animatorX.setDuration(400);
        animatorX.start();
    }

    /**
     * 移动到位置 (x,y)
     *
     * @param x
     * @param y
     */
    @Override
    public void moveTo(int x, int y) {
        moveTo(x, y, z);
    }

    @Override
    public void moveTo(ILayer layer) {
        ViewGroup viewGroup = getParentViewGroup();
        if (viewGroup != null) {
            viewGroup.removeView(view);
        }
        layer.addWindow(this);
    }

    /**
     * 移动到位置 (x,y,z)
     *
     * @param x
     * @param y
     * @param z
     */
    @Override
    public void moveTo(int x, int y, int z) {
        animateMoveTo(x, y);
        if (this.z == z) {
            return;
        }
        ViewGroup layer = getParentViewGroup();
        if (layer != null) {
            layer.removeView(view);
            layer.addView(view, z);
            // TODO: 2018/9/13 consider again
        }
    }

    /**
     * 添加到层
     *
     * @param layer 层
     * @param x
     * @param y
     */
    @Override
    public void moveTo(ILayer layer, int x, int y) {
        if (layer == getParentViewGroup()) {
            moveTo(x, y);
            return;
        }
        ViewGroup originLayer = getParentViewGroup();
        if (originLayer != null) {
            originLayer.removeView(view);
        }
        layer.addWindow(this);
    }

    /**
     * 缩放到位置(w,h)
     *
     * @param width
     * @param height
     */
    @Override
    public void scaleTo(int width, int height) {
        ViewGroup.LayoutParams lp = view.getLayoutParams();
        lp.width = width;
        lp.height = height;
        view.setLayoutParams(lp);
    }

    @Nullable
    public final ViewGroup getParentViewGroup() {
        if (view != null && view.getParent() != null && view.getParent() instanceof ViewGroup) {
            return (ViewGroup) view.getParent();
        }
        return null;
    }

    private int lastX, lastY, measuredParentWidth, measuredParentHeight;
    private int offXAll, offYAll;

    protected boolean onTouchEvent(View v, MotionEvent event) {
        if (gestureDetector.onTouchEvent(event)) {
            return true;
        }
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                if (v.getParent() != null && v.getParent() instanceof ViewGroup) {
                    ViewGroup viewGroup = (ViewGroup) v.getParent();
                    measuredParentHeight = viewGroup.getMeasuredHeight();
                    measuredParentWidth = viewGroup.getMeasuredWidth();
                }
                offXAll = 0;
                offYAll = 0;
                break;
            case MotionEvent.ACTION_MOVE:
                int offX = x - lastX;
                int offY = y - lastY;
                if (offXAll < 50 && offYAll < 50) {
                    offXAll += offX;
                    offYAll += offY;
                    break;
                }
                // 判断边界值
                if (v.getLeft() + offX < 0) {
                    offX = -v.getLeft();
                } else if (v.getRight() + offX > measuredParentWidth) {
                    offX = measuredParentWidth - v.getRight();
                }
                if (v.getTop() + offY < 0) {
                    offY = -v.getTop();
                } else if (v.getBottom() + offY > measuredParentHeight) {
                    offY = measuredParentHeight - v.getBottom();
                }
                if (allowTouch) {
                    FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();
                    layoutParams.leftMargin += offX;
                    layoutParams.topMargin += offY;
                    view.setLayoutParams(layoutParams);
                    if (onWindowRepositionListener != null) {
                        onWindowRepositionListener.onWindowMove(layoutParams.leftMargin, layoutParams.topMargin);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }
        return true;
    }

    protected String getString(@StringRes int id) {
        return view.getContext().getString(id);
    }

    protected String getString(@StringRes int id,Object... formatArgs) {
        return view.getContext().getString(id, formatArgs);
    }

    /**
     * 在 onViewAttachedToWindow 方法调用前或方法内 调用此方法以显示 阴影
     * <b>注意，调用此方法，{@link BaseWindow#view} 有限制，参考
     * {@link ShadowUtil#setViewBoundShadow(View, int, int, int, ShadowUtil)}</b>
     *
     * @param isNeedShowShadow 传 true 以显示阴影
     */
    protected void setNeedShowShadow(boolean isNeedShowShadow) {
        needShowShadow = isNeedShowShadow;
    }

    protected boolean isAdmin() {
        return false;
    }

    private class WindowOnTouchListener implements View.OnTouchListener {
        @SuppressLint("ClickableViewAccessibility")
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return onTouchEvent(v, event);
        }
    }

    private class WindowGestureDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onDown(MotionEvent event) {
            if (isDestroy) {
                return false;
            }
            if (isAdmin()) {
                bringToForeground();
            }
            return super.onDown(event);
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            if (isDestroy) {
                return false;
            }
            if (onSingleTapListener != null) {
                onSingleTapListener.onSingleTapUp(e);
            }
            return true;
        }

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            if (onDoubleTapListener != null) {
                onDoubleTapListener.onDoubleTap(e);
            }
            return true;
        }
    }

    public void bringToForeground() {
        if (view != null) {
            view.bringToFront();
        }
    }

    public void setOnSingleTapListener(OnSingleTapListener onSingleTapListener) {
        this.onSingleTapListener = onSingleTapListener;
    }

    public interface OnSingleTapListener {
        void onSingleTapUp(MotionEvent event);
    }

    public interface OnDoubleTapListener {
        void onDoubleTap(MotionEvent e);
    }

    public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) {
        this.onDoubleTapListener = onDoubleTapListener;
    }

    public interface OnWindowRepositionListener {
        void onWindowMove(int x, int y);

        void OnWindowScale(int newWidth, int newHeight);
    }

    protected void setOnWindowRepositionListener(OnWindowRepositionListener onWindowRepositionListener) {
        this.onWindowRepositionListener = onWindowRepositionListener;
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy() {
        isDestroy = true;
        compositeDisposable.dispose();
        if (onWindowRepositionListener != null) {
            onWindowRepositionListener = null;
        }
        if (lifecycle != null) {
            lifecycle.removeObserver(this);
        }

        ViewGroup viewGroup = getParentViewGroup();
        if (viewGroup != null) {
            viewGroup.removeView(view);
        }
        lifecycle = null;
        $ = null;
    }

    public boolean isDestroy() {
        return isDestroy;
    }

    protected void unSubscribe() {
        compositeDisposable.clear();
    }
}
